package com.merry.beanFactory.bf;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * Spring bean容器的顶层接口：
 *      此接口由包含多个 {BeanDefinition} 的对象实现，每个 {BeanDefinition} 都由一个String名称唯一标识。
 *      根据 {BeanDefinition} ，工厂将返回包含对象的独立实例（原型设计模式）或单个共享实例（Singleton设计模式的高级替代方案，其中实例是工厂范围内的单例）。
 *      返回哪种类型的实例取决于bean工厂配置：API是相同的。自Spring 2.0以来，根据具体的应用程序上下文，可以使用更多的作用域（例如web环境中的“请求”和“会话”作用域）。
 *
 * 这种方法的要点是BeanFactory是应用程序组件的中央注册表，并集中配置应用程序组件（例如，单个对象不再需要读取属性文件）。
 * 关于这种方法的好处的讨论，请参阅“Expert One-on-One J2EE Design and Development”的第4章和第11章。
 *
 * 请注意，通常最好依靠依赖注入（“推送”配置）通过setter或构造函数配置应用程序对象，而不是使用任何形式的“拉取”配置，
 * 如BeanFactory查找。Spring的依赖注入功能是使用此BeanFactory接口及其子接口实现的。
 *
 * 通常，BeanFactory会加载存储在配置源（如XML文档）中的bean定义，并使用{@code org.springframework.beans}包来配置bean。
 * 然而，实现可以简单地返回它在必要时直接在Java代码中创建的Java对象。对定义的存储方式没有限制：LDAP、RDBMS、XML、属性文件等。鼓励实现支持bean之间的引用（依赖注入）。
 *
 * 与{@link ListableBeanFactory}中的方法不同，如果这是{@link HierarchicalBeanFactory}，
 * 则此接口中的所有操作也将检查父工厂。如果在此工厂实例中找不到bean，将询问直接父工厂。此工厂实例中的Bean应该覆盖任何父工厂中同名的Bean。
 *
 * {BeanFactory} 实现应尽可能支持标准bean生命周期接口。整套初始化方法及其标准顺序是：
 *      1. BeanNameAware's {@code setBeanName}
 *      2. BeanClassLoaderAware's {@code setBeanClassLoader}
 *      3. BeanFactoryAware's {@code setBeanFactory}
 *      4. EnvironmentAware's {@code setEnvironment}
 *      5. EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 *      6. ResourceLoaderAware's {@code setResourceLoader} （只适用于 ApplicationContext 容器）
 *      7. ApplicationEventPublisherAware's {@code setApplicationEventPublisher} （只适用于 ApplicationContext 容器）
 *      8. MessageSourceAware's {@code setMessageSource} （只适用于 ApplicationContext 容器）
 *      9. ApplicationContextAware's {@code setApplicationContext} （只适用于 ApplicationContext 容器）
 *      10. ServletContextAware's {@code setServletContext} （只适用于 WebApplicationContext 容器）
 *      11. {@code postProcessBeforeInitialization} methods of BeanPostProcessors （BeanPostProcessor 的前置处理方法）
 *      12. InitializingBean's {@code afterPropertiesSet} （bean的初始化方法，也就是 afterPropertiesSet方法）
 *      13. 自定义的 {init-method} 方法。
 *      14. {@code postProcessAfterInitialization} methods of BeanPostProcessors （beanPostProcessor 的后置处理方法）
 *
 *在关闭 {beanFactory} 时，应该遵循下面的流程：
 *      1. {@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors 没找到这个接口。
 *      2. DisposableBean's {@code destroy} DisposableBean的destroy方法。
 *      3. 自定义的 {destroy-method} 方法
 *
 *
 * 在接口的定义中，我们可以看到一些Bean的声明周期的定义，比如上面说了，生成一个bean和销毁一个bean都应该遵循一些标准顺序。
 */
public interface BeanFactory {

    /**
     * 用于区分当前bean是不是一个工厂bean。 {@link FactoryBean} 。比如 {@code myJndiObject} 是一个 FactoryBean。
     * 那么生成这个bean的工厂就应该是 {@code &myJndiObject}
     */
    String FACTORY_BEAN_PREFIX = "&";


    /**
     * 根据名字，返回一个bean的实例。
     */
    Object getBean(String name) throws BeansException;

    /**
     * 根据类型和名字，返回一个bean的实例。
     */
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    /**
     * 根据名字，返回bean的实例，参数为创建bean是使用的参数。
     */
    Object getBean(String name, Object... args) throws BeansException;

    /**
     * 根据类型，返回一个bean的实例，如果容器中有多个相同类型的实例，则会抛出异常。
     */
    <T> T getBean(Class<T> requiredType) throws BeansException;

    /**
     * 根据类型，返回实例。
     */
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    /**
     * Return a provider for the specified bean, allowing for lazy on-demand retrieval
     * of instances, including availability and uniqueness options.
     * @param requiredType type the bean must match; can be an interface or superclass
     * @return a corresponding provider handle
     * @since 5.1
     * @see #getBeanProvider(ResolvableType)
     */
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

    /**
     * Return a provider for the specified bean, allowing for lazy on-demand retrieval
     * of instances, including availability and uniqueness options.
     * @param requiredType type the bean must match; can be a generic type declaration.
     * Note that collection types are not supported here, in contrast to reflective
     * injection points. For programmatically retrieving a list of beans matching a
     * specific type, specify the actual bean type as an argument here and subsequently
     * use {@link ObjectProvider#orderedStream()} or its lazy streaming/iteration options.
     * @return a corresponding provider handle
     * @since 5.1
     * @see ObjectProvider#iterator()
     * @see ObjectProvider#stream()
     * @see ObjectProvider#orderedStream()
     */
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    /**
     * 判断当前容器中，是否包含这个bean。
     */
    boolean containsBean(String name);

    /**
     * 判断当前bean是不是一个单例bean。
     */
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    /**
     * 判断当前bean是不是一个原型链bean。
     */
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    /**
     * 根据beanName，判断容器中的bean是不是和入参 {typeToMatch} 类型匹配。
     */
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    /**
     * 一样的，类型匹配。
     */
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    /**
     * 获取当前beanName的class对象。
     * 注意，如果name是一个工厂bean，则会返回这个工厂的class。
     */
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    /**
     * 获取当前bean的class对象。
     * 注意，如果name是一个工厂bean，则会调用 {@link FactoryBean#getObjectType()} 方法，获取bean的class，而不是工厂的。
     */
    @Nullable
    Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

    /**
     * 获取bean的所有别名。
     */
    String[] getAliases(String name);

}
